package scfg.utils;

import java.io.File;
import java.util.*;

import desposito6.math.MyBigDecimal;
import desposito6.math.iDouble;

import scfg.RNAStatsObj;
import scfg.RNAobj;
import scfg.output.Display;
import scfg.output.RNAFormattedFile;

public class CustomDistrobutionAnalyzer {

	private static boolean enableExtraConstraints = false;

	public static RNAStatsObj processFile(String filename) {
		if (filename != null)
			return processFile(new File(filename));
		// TODO:
		return null;
	}
	
	public static RNAStatsObj processFile(File rnaFile) {
		if (rnaFile == null || !rnaFile.exists() || !rnaFile.isFile()){
			// TODO: 
//			System.err.println("ARGS: " + f.getAbsolutePath());
			return null;
		} else if (!rnaFile.getName().contains(".rna")) {
			// TODO: 
//			if(!f.getName().contains(".cnstr"))
//				System.err.println("NAME: " + f.getAbsolutePath());
			return null;
		}
		RNAFormattedFile rnaff = new RNAFormattedFile(rnaFile);
		if (rnaff != null && rnaff.get("seq") != null && rnaff.get("nat") != null && rnaff.get("mfe_gtcon") != null && rnaff.get("mfe_gtconX") != null) {
			return new RNAStatsObj(rnaFile.getName(), rnaff.get("seq"), rnaff.get("nat"), rnaff.get("mfe_gtcon"), rnaff.get("mfe_gtconX"), rnaff.get("mfe_gt"));
		}
		return null;
	}
	
	public static List<RNAStatsObj> processDir(String filename) {
		return processDir(new File(filename));
	}
	
	public static List<RNAStatsObj> processDir(File base) {
		if (base == null || !base.exists() || !base.isDirectory()){
			// TODO:
			return null;
		}
		File[] files = base.listFiles();
		Queue<File> dirs = new LinkedList<File>();
		List<RNAStatsObj> structures = new LinkedList<RNAStatsObj>();
		for (File f : files) {
			if (f.isDirectory())
				dirs.offer(f);
			else {
				RNAStatsObj temp = processFile(f);
				if (temp != null)
					structures.add(temp);
			}
		}
		while (!dirs.isEmpty()) {
			File f = dirs.poll();
			List<RNAStatsObj> temp = processDir(f);
			if (temp != null)
				structures.addAll(temp);
		}
		return structures;
	}
	
	public static void printCSVFile(List<RNAStatsObj> structures, String filename) {
		Display output = new Display(filename, null, false);
		output.out(filename);
		output.out("\"Ref BP's\",\"Ref Con BP's\",\"MFE BP's\",\"MFE Con BP's\",\"MFEX BP's\",\"MFEX Con BP's\",Seq Length");
		for (RNAStatsObj rna : structures) {
			Integer natBP = rna.getNatBasePairs();
			Integer natConBP = rna.getNatCanonicalBasePairs();
			Integer predBP = rna.getPredBasePairs();
			Integer predConBP = rna.getPredCanonicalBasePairs();
			Integer predXBP = rna.getPredXBasePairs();
			Integer predXConBP = rna.getPredXCanonicalBasePairs();
			Integer sequenceLength = rna.getSequenceLength();
			String RNAfilename = rna.getFileName();
			if (natBP != null && natConBP != null && predBP != null && predConBP != null && predXBP != null && predXConBP != null && sequenceLength != null){
				output.outC(rna.getNatBasePairs().toString()).outC(",").outC(rna.getNatCanonicalBasePairs().toString()).outC(",");
				output.outC(rna.getPredBasePairs().toString()).outC(",").outC(rna.getPredCanonicalBasePairs().toString()).outC(",");
				output.outC(rna.getPredXBasePairs().toString()).outC(",").outC(rna.getPredXCanonicalBasePairs().toString()).outC(",");
				output.out(rna.getSequenceLength().toString());
				handleRNAStatsObj(RNAfilename, natConBP, predBP, sequenceLength);
			} else {
				// TODO
			}
		}
		output.finalizeDisplay();
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		String filename = "/home/david/Documents/RNA/rna_files/approved_ct_files/5S/";
		List<RNAStatsObj> structures = processDir(filename);
		printCSVFile(structures, "5S_conStats.csv");
		System.out.println(Display.box("5S Done", "\t"));
		
		filename = "/home/david/Documents/RNA/rna_files/approved_ct_files/16S/";
		structures = processDir(filename);
		printCSVFile(structures, "16S_conStats.csv");
		System.out.println(Display.box("16S Done", "\t"));
		
		filename = "/home/david/Documents/RNA/rna_files/approved_ct_files/23S/";
		structures = processDir(filename);
		printCSVFile(structures, "23S_conStats.csv");
		System.out.println(Display.box("23S Done", "\t"));
		
		filename = "/home/david/Documents/RNA/rna_files/approved_ct_files/";
		structures = processDir(filename);
		printCSVFile(structures, "all_conStats.csv");
		
		System.out.println(Display.box("All Done", "\t"));
		
		writeSortedList(natSort, "referenceSortList.csv");
		writeSortedList(gtSort, "constrainedSortList.csv");
		writeSortedList(gtXSort, "constrainedSortList_X_.csv");
		
		System.out.println(Display.box("Files Written", "\t"));
	}
	
	private static List<CustPair> natSort, gtSort, gtXSort;
	private static Display natSortDisp, gtSortDisp, gtXSortDisp;
	
	static {
		natSort = new LinkedList<CustPair>();
		gtSort = new LinkedList<CustPair>();
		gtXSort = new LinkedList<CustPair>();
	}
	
	private static void handleRNAStatsObj(String filename, int natBP, int mfeBP, int seqLen) {
		CustPair natPair = new CustPair(filename, (double)natBP / (double)seqLen);
		CustPair mfePair = new CustPair(filename, (double)natBP / (double)mfeBP);
		if(!natSort.contains(natPair))
			natSort.add(natPair);
		if (enableExtraConstraints)
			gtXSort.add(mfePair);
		else
			gtSort.add(mfePair);
	}
	
	private static void writeSortedList(List<CustPair> sortList, String filename) {
		Collections.sort(sortList);
		Display temp = new Display(filename, null, false);
		temp.out(filename);
		temp.outC(sortList.size() + "").out(" sequences\n");
		for (CustPair p : sortList)
			temp.out(p.toString());
		temp.finalizeDisplay();
	}
	
	private static class CustPair implements Comparable<CustPair> {
		private iDouble val;
		private String filename;
		
		public CustPair(String filename, double val) {
			this (filename, new MyBigDecimal(val));
		}
		
		public CustPair(String filename, iDouble val) {
			this.filename = filename;
			this.val = val;
		}
		
		@Override
		public int compareTo(CustPair that) {
			return this.val.compareTo(that.val);
		}
		
		@Override
		public boolean equals(Object test) {
			if (test instanceof CustPair) {
				CustPair temp = (CustPair) test;
				return this.filename.equals(temp.filename);
			}
			return false;
		}
		
		@Override
		public String toString() {
			return val.toPlainString() + ",\"" + filename + "\"";
		}
	}
}
